package cn.edu.hust.cm.widgets;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;

import java.io.OutputStream;
import java.util.ArrayList;

import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.CropCircleTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;

/**
 * An custom ImageView which can load image from different source by using Glide.
 * <p>
 * version - 0.2 Feature - supports Round Corner & Image download
 * version - 0.1 Feature - supports Blur and Round
 */

public class GlideImageView extends ImageView {

    private boolean mRound;
    private boolean mBlur;
    private int mCornerRadius;

    private RequestManager mRequestManager;

    private String mUrl;
    private Object mExtraTag;

    public GlideImageView(Context context) {
        super(context);
    }

    public GlideImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GlideImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public GlideImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initGlideImageView(context, attrs, defStyleAttr, defStyleRes);
    }

    private void initGlideImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.GlideImageView, defStyleAttr, defStyleRes);
        mRound = a.getBoolean(R.styleable.GlideImageView_cm_round, false);
        mBlur = a.getBoolean(R.styleable.GlideImageView_cm_blur, false);
        mCornerRadius = a.getDimensionPixelSize(R.styleable.GlideImageView_cm_corner_radius, 0);
        a.recycle();

        if (mCornerRadius > 0) {
            mRound = false;
        }
    }

    public boolean isRound() {
        return mRound;
    }

    public void setRound(boolean round) {
        if (mRound != round) {
            mRound = round;

            // FIXME
            // invalidate();

            if (mRound) {
                mCornerRadius = 0;
            }
        }
    }

    public boolean isBlur() {
        return mBlur;
    }

    public void setBlur(boolean blur) {
        if (mBlur != blur) {
            mBlur = blur;

            // FIXME
            // invalidate();
        }
    }

    public int getCornerRadius() {
        return mCornerRadius;
    }

    public void setCornerRadius(int cornerRadius) {
        if (mCornerRadius != cornerRadius) {
            mCornerRadius = cornerRadius;

            if (mCornerRadius > 0) {
                mRound = false;
            }
        }
    }

    public RequestManager getRequestManager() {
        return mRequestManager;
    }

    /**
     * Specify a requestManager for this instance.
     * <p>
     * Note - when loading image, the specified requestManager will be preferred
     *
     * @param requestManager RequestManager
     */
    public void setRequestManager(RequestManager requestManager) {
        if (mRequestManager != requestManager) {
            mRequestManager = requestManager;
        }
    }

    /**
     * Load image from file path.
     *
     * @param path File path
     */
    public void setImagePath(String path) {
        setImageUrl(path);
    }

    /**
     * Load image from url.
     *
     * @param url Url
     */
    public void setImageUrl(String url) {
        mUrl = url;
        ArrayList<Transformation> array = new ArrayList<>();
        final Context context = getContext();
        if (mBlur) {
            array.add(new BlurTransformation(context));
        }
        if (mRound && mCornerRadius == 0) {
            array.add(new CropCircleTransformation(context));
        }
        if (mCornerRadius > 0) {
            // ensure RoundedCornersTransformation worked
            array.add(new CenterCrop(context));
            array.add(new RoundedCornersTransformation(context, mCornerRadius, 0));
        }

        if (mRequestManager == null) {
            if (array.isEmpty()) {
                Glide.with(context).load(url).asBitmap().into(this);
            } else {
                //noinspection unchecked
                Glide.with(context).load(url).asBitmap().transform(array.toArray(new Transformation[array.size()])).into(this);
            }
        } else {
            if (array.isEmpty()) {
                mRequestManager.load(url).asBitmap().into(this);
            } else {
                //noinspection unchecked
                mRequestManager.load(url).asBitmap().transform(array.toArray(new Transformation[array.size()])).into(this);
            }
        }
    }

    public String getUrl() {
        return mUrl;
    }

    public Object getExtraTag() {
        return mExtraTag;
    }

    public void setExtraTag(Object tag) {
        mExtraTag = tag;
    }

    /**
     * Save current image bitmap to the specified stream.
     *
     * @param stream OutputStream
     * @return True if succeed, otherwise false
     */
    public boolean saveImageBitmap(OutputStream stream) {
        final Drawable drawable = getDrawable();
        if (drawable != null && drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null) {
                return bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            }
        }
        return false;
    }

    public static class GlideImageViewFactory {
        private static GlideImageViewFactory sInstance = new GlideImageViewFactory();

        public static GlideImageViewFactory getInstance() {
            return sInstance;
        }

        public View newImageView(Context context, String url, Object tag) {
            GlideImageView imageView = new GlideImageView(context);

            imageView.setScaleType(ScaleType.CENTER_CROP);
            imageView.setExtraTag(tag);
            imageView.setImageUrl(url);

            return imageView;
        }
    }
}
